// 1. clone/deepclone
// 2. new
// 3. object.create
// 4. instanceof
// 5. lodash.get/memorize

function deepclone(obj, weakMap = new WeakMap()){
    if(obj instanceof Date){
        return  new Date(obj)
    }
    if(obj instanceof RegExp){
        return new RegExp(obj)
    }

    if(typeof obj !== "object" || obj === null){
        return obj
    }

    if(weakMap.has(obj)){
        return weakMap.get(obj)
    }

    let C = obj.constructor;
    let res = new C();
    weakMap.set(obj, res)

    Object.keys(obj).forEach(item => {
        if(obj.hasOwnProperty(item)){
                res[item] = deepclone(obj[item], weakMap)
        }
    })
    return res;
}

console.log(deepclone({
    a: 1,
    b: '22',
    c: new Date(),
    d: /^[4]/,
    e: {n: 'n'},
}))


function clone(obj){
    if(obj instanceof Date){
        return  new Date(obj)
    }
    if(obj instanceof RegExp){
        return new RegExp(obj)
    }

    if(typeof obj !== "object" || obj === null){
        return obj
    }
    let C= obj.constructor;
    let res = new C()
    Object.keys(obj).forEach(item => {
        if(obj.hasOwnProperty(item)){
                res[item] = obj[item]
        }
    })
    return res;
}

console.log(clone({
    a: 1,
    b: '22',
    c: new Date(),
    d: /^[4]/,
    e: {n: 'n'},
}))


Object.myCreate = function(obj){
    function fn(){};
    fn.prototype = obj;
    return new fn()
}

function MyMew(fn, ...args){
    let newFn = Object.create(fn.prototype);
    let res = fn.call(newFn, ...args)
    return res instanceof Object ? res : newFn
}

function myInstanceof(obj,Obj){
    let ObjPrototype = Obj.prototype;
    let objPrototype = obj.__proto__;
    while(true){
        if(objPrototype=== null) return false
        if(ObjPrototype === objPrototype){
            return true
        }
        objPrototype = objPrototype.__proto__
    }
}
function A(){}
let a = new A();

console.log(myInstanceof(a, A))


function myLodashGet(obj, path, defaultValue){
    let paths = path;
    if(!Array.isArray(path)){
        paths = path.match(/[^\[\].]+/g)
        console.log(paths);
    }
    for(let i = 0; i< paths.length; i++){
        if(!obj) return defaultValue
       obj = obj[paths[i]] || defaultValue
    }
    return obj || defaultValue
}
const obj = {a: [{b: {c:3}}]}
console.log(myLodashGet(obj,['a', 0, 'b', 'c'], 1))
console.log(myLodashGet(obj,'a[0]b.c',0))


function memoize(fn, resolve){
    let weakMap = new WeakMap();
    const memoized = function(...args){
        const key = resolve ? resolve.call(this, ...args) : args[0]
        if(weakMap.has(key)) return weakMap.get(key)
        let res = fn.call(this, ...args)
        weakMap.set(key, res)
        return res;
    }
    return memoized;
}


var obj1 = {a: 1, b: 1}
var other = {c: 3, d: 4}

var values = memoize((obj) => Object.values(obj))
var values2 = memoize((obj) => Object.values(obj), () => ({}))
console.log(values(obj1))
obj1.a = 2
console.log(values2(obj1))
